﻿using fastNpoi.Attributes;
using fastNpoi.Model;
using NPOI.SS.Formula.Eval;
using NPOI.SS.UserModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace fastNpoi.Utils
{
    public class FastNpoiUtils
    {
        public static Dictionary<string, (PropertyInfo prop, NpoiAttribute attr)> GetHeaderAttrDic<T>(OperationType operationType,bool IsOrderby, Dictionary<PropertyInfo, NpoiAttribute> ExtraInfo)
            where T : class,new()
        {
            Dictionary<string, (PropertyInfo prop, NpoiAttribute attr)> result = new Dictionary<string, (PropertyInfo prop, NpoiAttribute attr)>();
            Type type = typeof(T);
            IEnumerable<PropertyInfo> propertyInfos = type.GetProperties().Where(t =>
            {
                if (ExtraInfo.TryGetValue(t, out NpoiAttribute dicAttr))
                {
                    return dicAttr.OperationType == operationType || dicAttr.OperationType == OperationType.Import_Export;
                }
                else
                {
                    var attr = t.GetCustomAttribute<NpoiAttribute>();
                    return attr != null && (attr.OperationType == operationType || attr.OperationType == OperationType.Import_Export);
                }
            });
            if (IsOrderby)
            {
                propertyInfos = propertyInfos.OrderBy(t =>
                {
                    if (ExtraInfo.TryGetValue(t, out NpoiAttribute dicAttr))
                    {
                        return dicAttr.Position;
                    }
                    else
                    {
                        return t.GetCustomAttribute<NpoiAttribute>()?.Position;
                    }
                });
            }
            foreach (PropertyInfo prop in propertyInfos)
            {
                NpoiAttribute attr;
                if (!ExtraInfo.TryGetValue(prop, out attr))
                {
                    attr = prop.GetCustomAttribute<NpoiAttribute>();
                }
                result.Add(attr.HeaderName, (prop, attr));

            }
            return result;
        }
        public static object GetExpPropertyName(Expression expression)
        {
            object value = "";
            if (expression is UnaryExpression)
            {
                value = ((MemberExpression)((UnaryExpression)expression).Operand).Member.Name;
            }
            else if (expression is MemberExpression)
            {
                value = ((MemberExpression)expression).Member.Name;
            }
            else if (expression is ParameterExpression)
            {
                value = ((ParameterExpression)expression).Type.Name;
            }
            else if (expression is ConstantExpression)
            {
                value = ((ConstantExpression)expression).Value;
            }
            return value;
        }
        public static object GetCellValue(ICell cell)
        {
            if (cell == null) return "";
            object value = null;
            switch (cell.CellType)
            {
                case CellType.Numeric:    //用于取出数值和公式类型的数据 
                    value = DateUtil.IsCellDateFormatted(cell) ? cell.DateCellValue.ToString("yyyy-MM-dd") : cell.NumericCellValue.ToString();
                    break;
                case CellType.Error:
                    value = ErrorEval.GetText(cell.ErrorCellValue);
                    break;
                case CellType.Formula:
                    switch (cell.CachedFormulaResultType)
                    {
                        case CellType.String:
                            string strFORMULA = cell.StringCellValue;
                            if (strFORMULA != null && strFORMULA.Length > 0)
                            {
                                value = strFORMULA.ToString();
                            }
                            break;
                        case CellType.Numeric:
                            value = Convert.ToString(cell.NumericCellValue);
                            break;
                        case CellType.Boolean:
                            value = Convert.ToString(cell.BooleanCellValue);
                            break;
                        case CellType.Error:
                            value = ErrorEval.GetText(cell.ErrorCellValue);
                            break;
                        default:
                            value = "";
                            break;
                    }
                    break;
                case CellType.Boolean:
                    // Boolean type
                    value = cell.BooleanCellValue.ToString();
                    break;

                case CellType.Blank:
                    break;

                default:
                    // String type
                    value = cell.StringCellValue.Trim();
                    break;
            }
            return value;
        }
    }
}
